ui-router is routing framework for AngularJS。
ui-router 不是 AngularJS 原生的 router module,$router 才是。
ui-router 跟 $router 的差別在於 ui-route 組織在 state,而 $router 是組織在 url。
( stete 是 ui-router 定義網站指定頁面的狀態。例如:登入頁,state: 'singIn')
打個比方,你有個 <a> tag 連結到登入頁。
ui-route 的寫法:
<a ui-sref=“main.signIn"></a> // base on state name
$route 的寫法:
<a href=“main/signIn” ></a> // base on url
signIn 的 link 需要出現在很多頁面上。
假使,有一天需求變更。需要把 singIn 的 uri 變成 /signIn (前面 main/ 拿掉)。
使用 AngularJS $route 就需要確保每頁 singIn url 都有更新成 <a href=“/signIn”></a> (多個動作)
可是 ui-route 只需要在定義 state name 的地方把定義的 url 換成新的就好了。(一個動作)
接下來進入 ui-router 的介紹吧!
ui-sref directive:
ui-sref directive 讓綁定 element 變成到指定 state 的連結。
假如 element 是 <a> tag 的話,還會自動產生 href attribute 在 <a> tag上面。
先看範例 http://plnkr.co/edit/NajjDAov6bWJuct28yxQ?p=preview
var app = angular.module('myExample', ['ui.router']);
app.config( function( $stateProvider, $urlRouterProvider ) {
$urlRouterProvider.otherwise('/home');
// 定義 $state
$stateProvider
.state('home', {
url: '/home',
template: '<div>我在主頁</div>'
})
.state('about', {
url: '/about/:id',
template: '<div>我在介紹 {{id}}</div>',
controller: function ($scope, $stateParams) {
$scope.id = $stateParams.id;
}
});
});
<div ng-controller="myCtrl">
<!-- ui-sref 會幫忙產生對應的 href -->
<a ui-sref="home" ui-sref-active="active">主頁</a>
<!-- 可以 pass parameters -->
<a ui-sref="about({'id':1})" ui-sref-active="active">介紹1</a>
<!-- 也可以直接定義 href 的方式,只是就沒用到優秀的 ui-router state 特性-->
<a href="#/about/2">介紹2</a>
<!-- bind ngClick + $state.go 也可以 work, 只是這樣不會自動產生 href -->
<a ng-click="$state.go('about', {'id': 3})">介紹3</a>
<!-- 不用 a tag 也可以 work, 可是就不會自動產生 href -->
<span ui-sref="about({'id':4})" ui-sref-active="active">介紹4</span>
</div>
由於 <a> tag + ui-sref 會自動幫忙產生 href attribute,方便使用者在連接用另開分頁 (ctrl-clicking) 形式打開。
建議除非想要在轉換 state 前做些準備事情,要不然採取 <a> tag + ui-sref 的方式就行。
ui-sref-active=“[class name]” :
假如相鄰的 ui-sref 定義的 state 跟當下的 state 一樣,就會在 element add 或 remove class。
ui-sref-avtive-eq=“[class name]" :
會判斷是完全一模一樣的 state 才會幫忙加 class。
ui-sref-active 跟 ui-sref-avtive-eq 的差別就是前者用 $state.include() 判斷,後者用 ==。
resolve function:
resolve function 是在 state 還沒有進入 controller 跟 render template 前會呼叫的 function。
適合用來準備下一個 state 頁面的顯示資料。
如果準備資料發生錯誤,會維持在當下的 state ,不會跳到下一個 state 。
$stateProvider.state('about', {
url: '/about/:id',
template: '<div>我在介紹 {{id}}</div><div>{{myAbout}}</div>',
// 一定要是 object 形式
resolve: {
'aboutData': function () {
return '我是要進介紹頁的文字'
}
},
// 在 controller inject resolve state 的 name, 就可以確保 data 在進 controller 前是準備好的
// aboutData 是可以拿取 resolve data 的方式
// 就算沒有 inject resolve function name, resolve function 還是會確保在 enter controller 前跑完
controller: function ($scope, $stateParams, aboutData) {
$scope.id = $stateParams.id;
$scope.myAbout = aboutData;
}
可以搭配 AngularJS 的 $q 來使用。當資料錯誤時,呼叫 $q.reject 會使得 state 回到上一個 state 中。
// 一定要是 object 形式, 可有複數
resolve: {
'aboutData': function () {
return '我是要進介紹頁的文字'
},
'myData': function ($q, $timeout, $stateParams) {
var d = $q.defer();
$timeout(function () {
if ($stateParams.id !== 1) {
// 錯誤發生, 預設保留在 $state.$current
d.reject();
} else {
d.resolve('myData');
}
}, 100);
return d.promise;
}
}
範例 http://plnkr.co/edit/4faEi0LvUgtYAMihRA74?p=preview